package validator

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

const VALIDATE = "validate"

type Validator struct {
}

func (v *Validator) Verify(obj any) error {
	valueOf := reflect.ValueOf(obj)
	typeOf := reflect.TypeOf(obj)

	if valueOf.IsNil() {
		return fmt.Errorf("传递对象不能为空")
	}

	if typeOf.Kind() == reflect.Ptr {

		if valueOf.IsNil() {
			return fmt.Errorf("传递对象不能为空")
		}

		typeOf = typeOf.Elem()
		valueOf = valueOf.Elem()
	}

	for i := range typeOf.NumField() {

		field := valueOf.Field(i)
		fieldType := typeOf.Field(i)

		structTag := fieldType.Tag
		validData := structTag.Get(VALIDATE)

		if validData == "" {
			continue
		}

		single, msg := ruleClassify(validData)

		for _, item := range single {

			if err := validateRule(fieldType.Name, field, item, msg); err != nil {
				return err
			}

		}
	}

	return nil
}

func ruleClassify(tag string) (single []string, msg string) {
	rules := strings.Split(tag, ",")
	for _, rule := range rules {
		if strings.Contains(rule, "=") {
			if strings.HasPrefix(rule, "msg=") {
				msg = strings.TrimPrefix(rule, "msg=")
			} else {
				single = append(single, rule)
			}
		} else {
			single = append(single, rule)
		}
	}
	return
}

// validateRule 验证规则
func validateRule(fieldName string, value reflect.Value, rule string, msg string) error {
	if strings.Contains(rule, "=") {
		split := strings.Split(rule, "=")
		k, v := split[0], split[1]
		switch k {
		case "len":
			// 长度
			return validateLen(fieldName, v, value, msg)
		case "eq",
			"ne",
			"lte",
			"lt",
			"gte",
			"gt",
			"min",
			"max":
			// 等于
			return validateOperate(fieldName, k, v, value, msg)
		default:
			return errors.New(rule + "不支持的规则")
		}
	} else {
		switch rule {
		case "required":
			// 不能为空
			switch value.Kind() {
			case reflect.String:
				if value.String() == "" {
					return errors.New(fieldName + "不能为空")
				}
			default:
			}
		case "email":

		}
	}

	return nil
}

func buildError(msg string, err error) error {
	if msg == "" {
		return err
	} else {
		return errors.New(msg)
	}
}

func validateLen(fieldName, value string, field reflect.Value, msg string) error {
	var (
		v   int
		err error
	)
	if v, err = strconv.Atoi(value); err != nil {
		return errors.New(fieldName + "验证规则不正确")
	}
	switch field.Type().Kind() {
	case reflect.String:
		if len(field.String()) != v {
			return buildError(msg, fmt.Errorf(fieldName+"长度必须为%d", v))
		}
	case reflect.Array, reflect.Slice:
		if field.Len() != v {
			return buildError(msg, fmt.Errorf(fieldName+"长度必须为 %d", v))
		}
	default:
	}
	return err
}

func validateOperate(fieldName, opr string, value string, field reflect.Value, msg string) error {
	var (
		v   int64
		v1  uint64
		v2  float64
		err error
	)
	switch field.Type().Kind() {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64:
		if v, err = strconv.ParseInt(value, 10, 64); err != nil {
			return errors.New(fieldName + "验证规则不正确")
		}
		switch opr {
		case "ne":
			if field.Int() != v {
				return buildError(msg, fmt.Errorf(fieldName+"必须不为 %d", v))
			}
		case "eq":
			if field.Int() == v {
				return buildError(msg, fmt.Errorf(fieldName+"必须为 %d", v))
			}
		case "lt":
			if field.Int() < v {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于 %d", v))
			}
		case "lte":
			if field.Int() <= v {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于等于 %d", v))
			}
		case "gt":
			if field.Int() > v {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于 %d", v))
			}
		case "gte":
			if field.Int() >= v {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于等于 %d", v))
			}
		case "min":
			if field.Int() < v {
				return buildError(msg, fmt.Errorf(fieldName+"最小 %d", v))
			}
		case "max":
			if field.Int() > v {
				return buildError(msg, fmt.Errorf(fieldName+"最大 %d", v))
			}
		}
	case reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64:
		if v1, err = strconv.ParseUint(value, 10, 64); err != nil {
			return errors.New(fieldName + "验证规则不正确")
		}

		switch opr {
		case "ne":
			if uint64(field.Int()) != v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须不为 %d", v))
			}
		case "eq":
			if uint64(field.Int()) == v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须为 %d", v))
			}
		case "lt":
			if uint64(field.Int()) < v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于 %d", v))
			}
		case "lte":
			if uint64(field.Int()) <= v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于等于 %d", v))
			}
		case "gt":
			if uint64(field.Int()) > v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于 %d", v))
			}
		case "gte":
			if uint64(field.Int()) >= v1 {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于等于 %d", v))
			}
		case "min":
			if uint64(field.Int()) < v1 {
				return buildError(msg, fmt.Errorf(fieldName+"最小 %d", v))
			}
		case "max":
			if uint64(field.Int()) > v1 {
				return buildError(msg, fmt.Errorf(fieldName+"最大 %d", v))
			}
		}
	case reflect.Float32, reflect.Float64:
		if v2, err = strconv.ParseFloat(value, 64); err != nil {
			return errors.New(fieldName + "验证规则不正确")
		}

		switch opr {
		case "ne":
			if field.Float() != v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须不为 %d", v))
			}
		case "eq":
			if field.Float() == v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须为 %d", v))
			}
		case "lt":
			if field.Float() < v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于 %d", v))
			}
		case "lte":
			if field.Float() <= v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须小于等于 %d", v))
			}
		case "gt":
			if field.Float() > v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于 %d", v))
			}
		case "gte":
			if field.Float() >= v2 {
				return buildError(msg, fmt.Errorf(fieldName+"必须大于等于 %d", v))
			}
		case "min":
			if field.Float() < v2 {
				return buildError(msg, fmt.Errorf(fieldName+"最小 %d", v))
			}
		case "max":
			if field.Float() > v2 {
				return buildError(msg, fmt.Errorf(fieldName+"最大 %d", v))
			}
		}
	case reflect.String:

		switch opr {
		case "ne":
			if field.String() != value {
				return buildError(msg, fmt.Errorf(fieldName+"必须不为 %d", v))
			}
		case "eq":
			if field.String() == value {
				return buildError(msg, fmt.Errorf(fieldName+"必须为 %d", v))
			}
		case "lt":
		case "lte":
		case "gt":
		case "gte":
		case "min":
		case "max":
			return fmt.Errorf(fieldName+"不支持验证规则", v)
		}
	default:

	}
	return err
}
